﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

using BaseCardTypes = Wormhole.Engine.CardLibrary.BaseCardTypes;

namespace Wormhole.UI.Application.Controls.Cards
{
	/// <author>Rodney McKay</author>
	/// <date>06 April 2008</date>
    /// <summary>
	/// The base class for all UI cards.
    /// </summary>
	public abstract class Card : Grid
	{
		#region Events
		/// <summary>
		/// Single click event.
		/// </summary>
		public event EventHandler Click;

		/// <summary>
		/// Double click.
		/// </summary>
		public event EventHandler DoubleClick;
		#endregion

		#region Declarations
		/// <summary>
		/// These declarations are used to distinguish beteween a single and a double click on the card.
		/// </summary>
		private bool isFirstClick = true;
		private bool isDoubleClick = false;
		private System.Windows.Forms.Timer doubleClickTimer = new System.Windows.Forms.Timer();
		private int timeBetweenClicks = 0;
		#endregion

		#region Properties
		/// <summary>
		/// The card that the control will render.
		/// </summary>
		public BaseCardTypes.Card EngineCard { get; set; }

		/// <summary>
		/// The image of the card.
		/// </summary>
		protected BitmapImage imageSource { get; set; }

		/// <summary>
		/// The game engine.
		/// </summary>
		public Engine.Game Game
		{
			get
			{
				if (this.EngineCard != null)
					return this.EngineCard.Owner.Game;

				return null;
			}
		}
		#endregion

		#region User Interface Elements
		/// <summary>The white outside border of the card.</summary>
		protected Border outsideBorder;

		/// <summary>The black border of the card.</summary>
		protected Border blackBorder;
		
		/// <summary>The content container grid.</summary>
		protected Grid contentGrid;

		/// <summary>The card image.</summary>
		protected Image cardImage;

		/// <summary>The card glow effect.</summary>
		protected OuterGlowBitmapEffect glowEffect;

		/// <summary>The card status.</summary>
		protected Status.CardStatus status;
		#endregion

		#region Constructor

		/// <summary>
		/// Create a default instance of the card.
		/// </summary>
		public Card()
		{
			this.CreateChildControls();
			this.SetSize();

			// wire up the event for the click timer
			this.doubleClickTimer.Interval = 1;
			this.doubleClickTimer.Tick += new EventHandler(doubleClickTimer_Tick);
		}

		/// <summary>
		/// Create a new instance of the class to render a engine card.
		/// </summary>
		/// <param name="card">The card form the enigne that should be rendered.</param>
		public Card(BaseCardTypes.Card card) : this()
		{
			this.EngineCard = card;
			this.EngineCard.InputStatusChanged += new Wormhole.Engine.CardLibrary.BaseCardTypes.Card.InputStatusChangedDelegate(EngineCard_InputStatusChanged);

			this.LoadImage();
			this.DisplayImage();
			this.CreateStatusControl();
		}

		#region Static Constructor
		///// <summary>
		///// Create a default instance of the class.
		///// </summary>
		//static Card()
		//{
		//    DefaultStyleKeyProperty.OverrideMetadata(typeof(Card), new FrameworkPropertyMetadata(typeof(Card)));
		//}
		#endregion
		#endregion

		#region Create Child Controls
		/// <summary>
		/// Create the child controls.
		/// </summary>
		protected virtual void CreateChildControls()
		{
			// create the outside border
			this.outsideBorder = new Border();
			this.outsideBorder.BorderBrush = Brushes.LightGray;
			this.outsideBorder.BorderThickness = new Thickness(1);
			this.outsideBorder.CornerRadius = new CornerRadius(4);
			this.Children.Add(this.outsideBorder);

			// create the black border
			this.blackBorder = new Border();
			this.blackBorder.Background = Brushes.Black;
			this.blackBorder.CornerRadius = new CornerRadius(4);
			this.outsideBorder.Child = this.blackBorder;

			// create the child grid
			this.contentGrid = new Grid();
			this.blackBorder.Child = this.contentGrid;

			// create the card image
			this.cardImage = new Image();
			this.contentGrid.Children.Add(this.cardImage);

			// create the outer glow
			this.glowEffect = new OuterGlowBitmapEffect();
			this.glowEffect.GlowColor = Colors.LawnGreen;
			this.glowEffect.Opacity = 0; // set to 1 to display
			this.glowEffect.GlowSize = 7;
			this.cardImage.BitmapEffect = this.glowEffect;

		}
		#endregion

		#region Create Status Control
		/// <summary>
		/// Create the status control.
		/// </summary>
		protected void CreateStatusControl()
		{
			if (this.EngineCard is BaseCardTypes.SkillsCard)
			{
				this.status = new Wormhole.UI.Application.Controls.Status.CardStatus((BaseCardTypes.SkillsCard)this.EngineCard);
				this.status.Margin = new Thickness(22);
				this.contentGrid.Children.Add(this.status);
			}
		}
		#endregion

		#region Set Size
		/// <summary>
		/// Set the size of the control.
		/// </summary>
		protected abstract void SetSize();
		#endregion

		#region Load Image
		/// <summary>
		/// Load the card image.
		/// </summary>
		protected void LoadImage()
		{
			this.imageSource = new BitmapImage(this.EngineCard.ImageUri);
		}
		#endregion

		#region Display Image
		/// <summary>
		/// Display the card image.
		/// </summary>
		protected virtual void DisplayImage()
		{
			CroppedBitmap croppedBitmap = new CroppedBitmap(this.imageSource, new Int32Rect(0, 0, 218, 200));
			this.cardImage.Source = croppedBitmap;

			BaseCardTypes.SkillsCard skillsCard = this.EngineCard as BaseCardTypes.SkillsCard;
			if (skillsCard != null)
			{
				if (!skillsCard.IsVillainCard)
				{
					this.DisplayHeroSkillsCard();
				}
			}
		}
		#endregion

		#region Display Hero Skills Card
		/// <summary>
		/// Display a Hero Skills Card
		/// </summary>
		private void DisplayHeroSkillsCard()
		{
			BaseCardTypes.SkillsCard skillsCard = this.EngineCard as BaseCardTypes.SkillsCard;

			// load the images that will blank out values
			BitmapSource blankSkill = new BitmapImage(new Uri("pack://application:,,,/Wormhole.UI.Application;component/images/blankSkill.png"));
			BitmapSource blankCost = new BitmapImage(new Uri("pack://application:,,,/Wormhole.UI.Application;component/images/blankCost.png"));

			// get the drawing context
			DrawingVisual drawingVisual = new DrawingVisual();
			DrawingContext drawingContext = drawingVisual.RenderOpen();

			// draw the card image
			CroppedBitmap croppedBitmap = new CroppedBitmap(this.imageSource, new Int32Rect(0, 0, 218, 200));
			drawingContext.DrawImage(croppedBitmap, new Rect(0, 0, croppedBitmap.Width, croppedBitmap.Height));

			// hideThe cost
			drawingContext.DrawImage(blankCost, new Rect(0, 0, 32, 43));

			// hide the skills
			if (skillsCard.Skills.Culture != null)
					drawingContext.DrawImage(blankSkill, new Rect(26, 56, 10, 23));

			if (skillsCard.Skills.Science != null)
				drawingContext.DrawImage(blankSkill, new Rect(26, 85, 10, 23));

			if (skillsCard.Skills.Combat != null)
				drawingContext.DrawImage(blankSkill, new Rect(26, 115, 10, 23));

			if (skillsCard.Skills.Ingenuity != null)
				drawingContext.DrawImage(blankSkill, new Rect(26, 143, 10, 23));

			// draw the cost text
			this.DrawCostText(skillsCard.Cost.ToString(), drawingContext, 13, 13, Brushes.Black);

			// draw the skills text
			this.DrawSkillsText(skillsCard.Skills.Culture.ToString(), drawingContext, 26, 58, Brushes.Black);
			this.DrawSkillsText(skillsCard.Skills.Science.ToString(), drawingContext, 26, 87, Brushes.Black);
			this.DrawSkillsText(skillsCard.Skills.Combat.ToString(), drawingContext, 26, 117, Brushes.Black);
			this.DrawSkillsText(skillsCard.Skills.Ingenuity.ToString(), drawingContext, 26, 145, Brushes.Black);
			
			// get the image source
			drawingContext.Close();
			RenderTargetBitmap targetBitmap = new RenderTargetBitmap(croppedBitmap.PixelWidth, croppedBitmap.PixelHeight, 96, 96, PixelFormats.Pbgra32);
			targetBitmap.Render(drawingVisual);

			// assign the image source
			this.cardImage.Source = targetBitmap;
		}
		#endregion

		#region Event Handlers

		#region Input Status Changed
		/// <summary>
		/// Handle the input status changed event.
		/// </summary>
		private void EngineCard_InputStatusChanged(Wormhole.Engine.CardLibrary.BaseCardTypes.InputStatus status)
		{
			this.Dispatcher.Invoke(
				DispatcherPriority.Normal,
				(System.Windows.Forms.MethodInvoker)delegate()
			{
				this.DisplayStatus();
			});
		}
		#endregion

		#region On Mouse Down
		/// <summary>
		/// Handle the mouse down event.
		/// </summary>
		/// <param name="e"></param>
		protected override void OnMouseDown(MouseButtonEventArgs e)
		{
			if (e.LeftButton == MouseButtonState.Pressed)
			{
				if (this.isFirstClick)
				{
					this.isFirstClick = false;
					this.doubleClickTimer.Start();
				}
				else
				{
					if (this.timeBetweenClicks < System.Windows.Forms.SystemInformation.DoubleClickTime)
						this.isDoubleClick = true;
				}
			}
		}
		#endregion

		#region Double Click Timer Tick
		/// <summary>
		/// This method is used to determine if a double or single click was executed.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void doubleClickTimer_Tick(object sender, EventArgs e)
		{
			this.timeBetweenClicks += 25;
			if (timeBetweenClicks > System.Windows.Forms.SystemInformation.DoubleClickTime)
			{
				this.doubleClickTimer.Stop();

				if (this.isDoubleClick)
					this.OnDoubleClick();
				else
					this.OnSingleClick();

				// reset the click members
				this.isFirstClick = true;
				this.isDoubleClick = false;
				this.timeBetweenClicks = 0;
			}
		}
		#endregion

		#region On Single Click
		/// <summary>
		/// Single click handler.
		/// </summary>
		protected virtual void OnSingleClick()
		{
			if (this.Click != null)
				this.Click(this, null);
		}
		#endregion

		#region On Double Click
		/// <summary>
		/// The Double click event handler.
		/// </summary>
		protected virtual void OnDoubleClick()
		{
			// select the card if it can be selected
			if (this.EngineCard.InputStatus == Wormhole.Engine.CardLibrary.BaseCardTypes.InputStatus.AllowSelect)
				this.EngineCard.SelectCard();

			// fire the double click event
			if (this.DoubleClick != null)
				this.DoubleClick(this, null);
		}
		#endregion

		#endregion

		#region Display Status
		/// <summary>
		/// Display the card status with the appropriate border.
		/// </summary>
		public virtual void DisplayStatus()
		{
			// hide the border
			this.glowEffect.Opacity = 0;

			// choose the glow color
			if (this.EngineCard.InputStatus == BaseCardTypes.InputStatus.AllowSelect)
				this.glowEffect.GlowColor = Colors.Yellow;
			else
				this.glowEffect.GlowColor = Colors.LawnGreen;

			// display the border when appropriate
			if ( (this.EngineCard.InputStatus == BaseCardTypes.InputStatus.AllowPlay) && (this.EngineCard.CanPlay()) )
				this.glowEffect.Opacity = 1;
			else if (this.EngineCard.InputStatus == BaseCardTypes.InputStatus.AllowSelect)
				this.glowEffect.Opacity = 1;
		}
		#endregion

		#region Draw Cast Text
		/// <summary>
		/// Draw card cost text.
		/// </summary>
		private void DrawCostText(string text, DrawingContext drawingContext, int x, int y, Brush brush)
		{
			// create the skills font type
			Typeface baseFont = new Typeface("Veranda");
			Typeface skillsFont = new Typeface(baseFont.FontFamily, FontStyles.Normal, FontWeights.Bold, FontStretches.Normal);

			// draw the text
			drawingContext.DrawText(
				   new FormattedText(text,
					  CultureInfo.GetCultureInfo("en-us"),
					  FlowDirection.LeftToRight,
					  skillsFont,
					  24, brush),
					  new Point(x, y));
		}
		#endregion

		#region Draw Skills Text
		/// <summary>
		/// Draw skills text on a card.
		/// </summary>
		private void DrawSkillsText(string text, DrawingContext drawingContext, int x, int y, Brush brush)
		{
			// create the skills font type
			Typeface baseFont = new Typeface("Veranda");
			Typeface skillsFont = new Typeface(baseFont.FontFamily, FontStyles.Normal, FontWeights.Bold, FontStretches.Normal);

			// draw the text
			drawingContext.DrawText(
				   new FormattedText(text,
					  CultureInfo.GetCultureInfo("en-us"),
					  FlowDirection.LeftToRight,
					  skillsFont,
					  15, brush),
					  new Point(x, y));
		}
		#endregion
	}
}
